package controlmercancias.datos;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import controlmercancias.configuracion.Configuracion;
import controlmercancias.configuracion.GestorConfiguracion;
import controlmercancias.dominio.Coordenada;
import controlmercancias.dominio.Medida;
import controlmercancias.dominio.Sensor;
import controlmercancias.dominio.Tren;
import controlmercancias.dominio.Tren.EstadoTren;
import controlmercancias.dominio.Usuario;

/**
 * Clase que actua con la base de datos.
 * @author Gonzalo
 *
 */
public class AccesoDatosBD extends AccesoDatosBDBase {

	@Override
	public synchronized Usuario getUsuario(String nombreUsuario, String password) {//FUNCIONA
		Usuario usuario = null;
		try {
			String sql = "SELECT administrador FROM usuario WHERE nombre = ? and password = ?";
			PreparedStatement ps = connection.prepareStatement(sql);
			ps.setString(1, nombreUsuario);
			ps.setString(2, password);
			ResultSet rs = ps.executeQuery();
			if (rs.next()){
				usuario = new Usuario();
				usuario.setNombre(nombreUsuario);
				usuario.setPassword(password);
			
				if (rs.getString("administrador").equals("Y")){
					usuario.setAdministrador(true);
				}else{
					usuario.setAdministrador(false);
				}
			}
			rs.close();
			ps.close();
			if (usuario != null){
				ArrayList <Tren> trenes = new ArrayList<Tren>();
				String sql2 = "SELECT id FROM usuario_has_tren WHERE nombre = ? ";
				PreparedStatement ps2 = connection.prepareStatement(sql2);
				ps2.setString(1, nombreUsuario);
				ResultSet rs2 = ps2.executeQuery();
				while (rs2.next()){
					trenes.add(getTren(rs2.getString("id")));
				}
				rs2.close();
				ps2.close();
				usuario.setListaTrenes(trenes);
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
		return usuario;
	}

	@Override
	public synchronized void setUsuario(Usuario u) {
		try{
			String sql = "UPDATE usuario SET password = ? , administrador = ? WHERE nombre = ?";
			PreparedStatement ps = connection.prepareStatement(sql);
			ps.setString(1, u.getPassword());
			ps.setBoolean(2, u.isAdministrador());
			ps.setString(3, u.getNombre());
			ps.executeUpdate();
			ps.close();
		}catch (Exception e){
			e.printStackTrace();
		}
		for (Tren t : u.getListaTrenes()){
			guardarDatosTren(t);
		}
	}

	@Override
	public synchronized void addUsuario(Usuario u) {//FUNCIONA
		try{
			String sql = "INSERT INTO usuario (nombre, password,administrador) VALUES (?,?,?)";
			PreparedStatement ps = connection.prepareStatement(sql);
			ps.setString(1, u.getNombre());
			ps.setString(2, u.getPassword());
			ps.setBoolean(3, u.isAdministrador());
			ps.executeUpdate();
			ps.close();
			for (Tren t : u.getListaTrenes()){
				String sql2 = "INSERT INTO usuario_has_tren (nombre,id) VALUES (?,?)";
				PreparedStatement ps2 = connection.prepareStatement(sql2);
				ps2.setString(1, u.getNombre());
				ps2.setString(2, t.getId());
				ps2.executeUpdate();
				ps2.close();
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public synchronized void deleteUsuario(Usuario u) {//FUNCIONA
		try{
			String sql = "DELETE FROM usuario WHERE nombre = ?";
			PreparedStatement ps = connection.prepareStatement(sql);
			ps.setString(1, u.getNombre());
			ps.executeUpdate();
			ps.close();
			String sql2 = "DELETE FROM usuario_has_tren WHERE nombre = ?";
			PreparedStatement ps2 = connection.prepareStatement(sql);
			ps2.setString(1, u.getNombre());
			ps2.executeUpdate();
			ps2.close();
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public synchronized boolean isUsuario(String nombreUsuario) { //FUNCIONA
		boolean existe = false;
		try{
			String sql = "SELECT * FROM usuario WHERE nombre = ?";
			PreparedStatement ps = connection.prepareStatement(sql);
			ps.setString(1, nombreUsuario);
			ResultSet rs = ps.executeQuery();
			existe = rs.next();
			rs.close();
			ps.close();
		}catch (Exception e) {
			e.printStackTrace();
		}
		return existe;
	}

	@Override
	public synchronized void guardarDatosTren(Tren t) {//FUNCIONA
		try{
		//ACTUALIZAR DATOS TREN
			{
			String sql = "UPDATE tren SET gps_conectado = ? , estado = ? WHERE id = ?";
			PreparedStatement ps = connection.prepareStatement(sql);
			ps.setBoolean(1, t.isGpsConnected());
			ps.setString(2, t.getEstado().toString());
			ps.setString(3, t.getId());
			ps.executeUpdate();
			ps.close();
			}
		//ACTUALIZAR SENSORES
		String sql = "UPDATE sensor SET descripcion = ? , estado = ? WHERE id=?";
			for (Sensor s : t.getSensores()){
				PreparedStatement ps = connection.prepareStatement(sql);
				ps.setString(1, s.getDesc());
				ps.setBoolean(2, s.isEstado());
				ps.setInt(3, s.getId());
				ps.executeUpdate();
				ps.close();
				insertarMedidas (s.getMedidas(),s.getId());
			}
			
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public synchronized List<Tren> getTrenes() {//FUNCIONA
		List<Tren> trenes = null;
		try{
			String sql = "SELECT * FROM tren";
			PreparedStatement ps = connection.prepareStatement(sql);
			ResultSet rs = ps.executeQuery();
			trenes = new ArrayList<Tren>();
			while(rs.next()){
				Tren tren = new Tren(rs.getString("id"));
				tren.setEstado(EstadoTren.getEstadoTrenFromString(rs.getString("Estado")));
				tren.setGpsConnected(rs.getBoolean("gps_conectado"));
				tren.setSensor(getSensores(tren.getId()));
				trenes.add(tren);
			}
		}catch (Exception e){
			e.printStackTrace();
		}
		return trenes;
	}
	@Override
	public synchronized List<Usuario> getAllUsuario() {
		List <Usuario> allUsuarios = new ArrayList<Usuario>();
		try{
			String sql = "SELECT nombre, password FROM usuario";
			PreparedStatement ps = connection.prepareStatement(sql);
			ResultSet rs = ps.executeQuery();
			while (rs.next()){
				allUsuarios.add(getUsuario(rs.getString("nombre"), rs.getString("password")));
			}
		}catch (Exception e){
			e.printStackTrace();
		}
		return allUsuarios;
	}

	/**
	 * Devuelve el tren con la id que se le pasa como parametro. Si no existe el tren es null.
	 * @param idTren
	 * @return Tren
	 */
	private synchronized Tren getTren(String idTren){//FUNCIONA
		Tren tren = null;
		try{
			String sql = "SELECT * FROM tren WHERE id = ?";
			PreparedStatement ps = connection.prepareStatement(sql);
			ps.setString(1, idTren);
			ResultSet rs = ps.executeQuery();
			if (rs.next()){
				tren = new Tren (idTren);
				tren.setEstado(EstadoTren.getEstadoTrenFromString(rs.getString("Estado")));
				tren.setGpsConnected(rs.getBoolean("gps_conectado"));
				tren.setSensor(getSensores(idTren));
			}
		}catch (Exception e){
			e.printStackTrace();
		}
		return tren;
	}
	/**
	 * Inserta en la BD la lista de medidas del sensor.
	 * @param medidas
	 * @param id_sensor
	 */
	private synchronized void insertarMedidas(List<Medida> medidas, int id_sensor) {//FUNCIONA
		List <Medida> medidasNoExistentes = listaMedidasAInsertar(medidas, id_sensor);
		try{
			String sql = "INSERT INTO medidas ( fecha, valor, latitud, longitud, id_sensor) values (?,?,?,?,?)";
			for (Medida m: medidasNoExistentes){
				PreparedStatement ps = connection.prepareStatement(sql);
				ps.setLong(1, m.getFecha().getTime());
				ps.setInt(2, m.getValor());
				ps.setString(3, m.getCoordenada().getLatitude());
				ps.setString(4, m.getCoordenada().getLongitude());
				ps.setInt(5, id_sensor);
				ps.executeUpdate();
				ps.close();
//				System.out.println(m);
			}
		}catch (Exception e){
			e.printStackTrace();
		}
	}
	/**
	 * Devuelve una lista de sensores que contiene la id del tren que se le pasa como parámetro.
	 * @param idTren
	 * @return List de sensores
	 */
	private synchronized List <Sensor> getSensores (String idTren){//FUNCIONA
		List <Sensor> lista = null;
		try{
			String sql = "SELECT * FROM sensor WHERE id_tren = ?";
			PreparedStatement ps = connection.prepareStatement(sql);
			ps.setString(1, idTren);
			ResultSet rs = ps.executeQuery();
			lista = new ArrayList<Sensor> ();
			while (rs.next()){
				Sensor s = new Sensor(rs.getInt("id"),rs.getString("descripcion"));
				s.setEstado(rs.getBoolean("estado"));
				s.setMedidas(getMedidas(s.getId()));
				lista.add(s);
			}
			rs.close();
			ps.close();
		}catch (Exception e) {
			e.printStackTrace();
		}
		return lista;
	}
	/**
	 * Retorna una lista de medidas del id sensor que se le pasa como parámetro.
	 * @param idSensor
	 * @return List de medidas
	 */
	private synchronized List <Medida> getMedidas (int idSensor){//FUNCIONA
		List <Medida> lista = null;
		try{
			String sql = "SELECT * FROM medidas WHERE id_sensor = ?";
			PreparedStatement ps = connection.prepareStatement(sql);
			ps.setInt(1, idSensor);
			ResultSet rs = ps.executeQuery();
			lista = new ArrayList<Medida> ();
			while (rs.next()){
				
				lista.add(new Medida(new Date(rs.getLong("fecha")), new Coordenada(rs.getString("latitud"),rs.getString("longitud")), rs.getInt("valor")));
			}
			rs.close();
			ps.close();
		}catch (Exception e) {
			e.printStackTrace();
		}
		return lista;
	}
	/**
	 * Comprueba las medidas que existen en la BD y si no existen se añade a una lista para retornarla.
	 * @param todasMedidas
	 * @param idSensor
	 * @return List medidas ha insertar
	 */
	private synchronized List <Medida> listaMedidasAInsertar (List <Medida> todasMedidas, int idSensor){
		List <Medida> listaMedidasHaInsertar = new ArrayList<Medida>();
		String sql = "SELECT * FROM medidas WHERE fecha = ? and id_sensor = ?";
		for (Medida m : todasMedidas){
			try{
				PreparedStatement ps = connection.prepareStatement(sql);
				ps.setLong(1, m.getFecha().getTime());
				ps.setInt(2, idSensor);
				ResultSet rs = ps.executeQuery();
				if (!rs.next()){
					listaMedidasHaInsertar.add(m);
				}
				rs.close();
				ps.close();
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
		return listaMedidasHaInsertar;
	}
public static void main (String [] args){
	GestorConfiguracion.cargarConfiguracion("BD/configuracionBD.properties");
    AccesoDatosBD.inicializarParametrosConexion(Configuracion.getInstance());
	AccesoDatosBD a = new AccesoDatosBD();
	a.init();
//	Tren tren1 = new Tren("1231");
//	Tren tren2 = new Tren("1232");
//	Tren tren3 = new Tren("1233");
//	Tren tren4 = new Tren("1234");
//	Tren tren5 = new Tren("1235");
//	ArrayList <Tren> trenes = new ArrayList<Tren>();
//	trenes.add(tren1);
//	trenes.add(tren2);
//	trenes.add(tren3);
//	trenes.add(tren4);
//	trenes.add(tren5);
//	Usuario u = new Usuario("hasier", "H", false, trenes);
//	a.setUsuario(u);
	List<Usuario> usuarios =	a.getAllUsuario();
	for (Usuario u : usuarios )
	{
		System.out.println(u.isAdministrador());
	}
}

}
